//! Phantom Types 虚类型
//!
//! Phantom Types（虚类型）是 Rust 中一种高级类型系统特性，它允许我们在类型层面
//! 编码额外的信息，而这些信息在运行时不占用任何空间。
//!
//! ## 知识点总结
//!
//! | 知识点 | 说明 | 使用场景 |
//! |--------|------|---------|
//! | PhantomData | 标记泛型参数的使用方式 | 编译时类型安全，零运行时开销 |
//! | 类型安全 | 防止不同类型之间的意外转换 | 单位系统，状态机等 |
//! | 零大小类型 | 不占用运行时内存 | 标记类型信息 |
//! | Variance | 协变和逆变关系 | 确保类型转换的安全性 |
//!
//! ## PhantomData 介绍
//!
//! `PhantomData<T>` 是一个零大小的标记类型，用于：
//! 1. 告诉编译器某个类型参数 T 被当前类型"拥有"或"使用"
//! 2. 在类型系统中携带额外的信息，但不增加运行时开销
//! 3. 确保类型安全，防止不同类型之间的意外转换
//!
//! ## 常见使用场景
//!
//! 1. **单位系统**：防止不同单位之间的错误转换
//! 2. **状态机**：在类型系统中编码状态信息
//! 3. **借用检查**：标记生命周期和借用关系
//! 4. **类型级编程**：在编译时进行类型计算
//!
//! ## 示例
//! ```rust
//! use std::marker::PhantomData;
//!
//! // 使用 PhantomData 创建单位类型
//! struct Meters PhantomData<f64>;
//! struct Kilograms PhantomData<f64>;
//!
//! // 带有 PhantomData 的泛型结构体
//! struct Container<T> {
//!     items: Vec<String>,
//!     _phantom: PhantomData<T>,
//! }
//! ```

use std::marker::PhantomData;

/// 1. 基本 PhantomData 使用
///
/// 展示如何使用 PhantomData 创建类型安全的包装类型
pub fn basic_phantom_data() {
    println!("=== 基本 PhantomData 使用 ===");

    // 定义两个不同的单位类型
    #[derive(Debug)]
    struct Meters;
    #[derive(Debug)]
    struct Kilograms;

    // 使用 PhantomData 创建类型安全的值
    #[derive(Debug)]
    struct Value<Unit> {
        value: f64,
        _phantom: PhantomData<Unit>,
    }

    // 为不同的单位类型实现构造函数
    impl<Unit> Value<Unit> {
        fn new(value: f64) -> Self {
            Value { value, _phantom: PhantomData }
        }

        fn value(&self) -> f64 {
            self.value
        }
    }

    // 创建不同单位的值
    let length = Value::<Meters>::new(5.0);
    let weight = Value::<Kilograms>::new(10.0);

    println!("长度: {} 米", length.value());
    println!("重量: {} 千克", weight.value());

    // 由于 PhantomData 的存在，这两个类型是不同的，不能直接比较或转换
    // 下面的代码会导致编译错误:
    // assert_eq!(length, weight); // 编译错误！
}

/// 2. 使用 PhantomData 表示所有权关系
///
/// 展示如何使用 PhantomData 标记结构体拥有或借用某种类型的数据
pub fn ownership_phantom_data() {
    println!("\n=== 使用 PhantomData 表示所有权关系 ===");

    // 标记拥有 T 类型数据的结构体
    struct Owns<T> {
        _phantom: PhantomData<T>,
    }

    impl<T> Owns<T> {
        fn new() -> Self {
            Owns { _phantom: PhantomData }
        }
    }

    // 标记借用 T 类型数据的结构体
    struct Borrows<'a, T> {
        _phantom: PhantomData<&'a T>,
    }

    impl<'a, T> Borrows<'a, T> {
        fn new() -> Self {
            Borrows { _phantom: PhantomData }
        }
    }

    let _owns_i32 = Owns::<i32>::new();
    let _borrows_string = Borrows::<String>::new();

    println!("创建了 Owns<i32> 和 Borrows<String> 实例");
}

/// 3. PhantomData 与类型转换
///
/// 展示如何使用 PhantomData 创建安全的类型转换系统
pub fn phantom_type_conversion() {
    println!("\n=== PhantomData 与类型转换 ===");

    // 定义不同的状态类型
    #[derive(Debug)]
    struct Celsius;
    #[derive(Debug)]
    struct Fahrenheit;

    // 温度类型，使用 PhantomData 标记状态
    #[derive(Debug)]
    struct Temperature<Scale> {
        degrees: f64,
        _phantom: PhantomData<Scale>,
    }

    impl<Scale> Temperature<Scale> {
        fn new(degrees: f64) -> Self {
            Temperature { degrees, _phantom: PhantomData }
        }

        fn degrees(&self) -> f64 {
            self.degrees
        }
    }

    // 定义转换函数
    fn celsius_to_fahrenheit(celsius: Temperature<Celsius>) -> Temperature<Fahrenheit> {
        let fahrenheit_degrees = celsius.degrees() * 9.0 / 5.0 + 32.0;
        Temperature::new(fahrenheit_degrees)
    }

    // 创建摄氏温度
    let celsius_temp = Temperature::<Celsius>::new(25.0);
    println!("摄氏温度: {:?}", celsius_temp);

    // 转换为华氏温度
    let fahrenheit_temp = celsius_to_fahrenheit(celsius_temp);
    println!("华氏温度: {:?}", fahrenheit_temp);
}

/// 主演示函数
pub fn demonstrate_phantom_types() {
    basic_phantom_data();
    ownership_phantom_data();
    phantom_type_conversion();

    println!("\n=== Phantom Types 总结 ===");
    println!("1. PhantomData 是零大小类型，不占用运行时内存");
    println!("2. PhantomData 用于在类型系统中携带额外信息");
    println!("3. PhantomData 可以帮助实现编译时类型安全");
    println!("4. PhantomData 常用于单位系统、状态机等场景");
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_basic_phantom_data() {
        #[derive(Debug)]
        struct Unit;

        #[derive(Debug)]
        struct Value<Unit> {
            value: f64,
            _phantom: PhantomData<Unit>,
        }

        impl<Unit> Value<Unit> {
            fn new(value: f64) -> Self {
                Value { value, _phantom: PhantomData }
            }

            fn value(&self) -> f64 {
                self.value
            }
        }

        let value = Value::<Unit>::new(42.0);
        assert_eq!(value.value(), 42.0);
    }

    #[test]
    fn test_ownership_phantom_data() {
        struct Owns<T> {
            _phantom: PhantomData<T>,
        }

        impl<T> Owns<T> {
            fn new() -> Self {
                Owns { _phantom: PhantomData }
            }
        }

        struct Borrows<'a, T> {
            _phantom: PhantomData<&'a T>,
        }

        impl<'a, T> Borrows<'a, T> {
            fn new() -> Self {
                Borrows { _phantom: PhantomData }
            }
        }

        let _owns = Owns::<i32>::new();
        let _borrows = Borrows::<String>::new();
    }

    #[test]
    fn test_phantom_type_conversion() {
        #[derive(Debug)]
        struct Celsius;
        #[derive(Debug)]
        struct Fahrenheit;

        #[derive(Debug)]
        struct Temperature<Scale> {
            degrees: f64,
            _phantom: PhantomData<Scale>,
        }

        impl<Scale> Temperature<Scale> {
            fn new(degrees: f64) -> Self {
                Temperature { degrees, _phantom: PhantomData }
            }

            fn degrees(&self) -> f64 {
                self.degrees
            }
        }

        fn celsius_to_fahrenheit(celsius: Temperature<Celsius>) -> Temperature<Fahrenheit> {
            let fahrenheit_degrees = celsius.degrees() * 9.0 / 5.0 + 32.0;
            Temperature::new(fahrenheit_degrees)
        }

        let celsius = Temperature::<Celsius>::new(0.0);
        let fahrenheit = celsius_to_fahrenheit(celsius);
        assert!((fahrenheit.degrees() - 32.0).abs() < f64::EPSILON);
    }

    #[test]
    fn test_demonstrate_phantom_types() {
        demonstrate_phantom_types();
    }

    #[test]
    fn test_phantom_data_size() {
        // 验证 PhantomData 是零大小类型
        assert_eq!(std::mem::size_of::<PhantomData<i32>>(), 0);
        assert_eq!(std::mem::size_of::<PhantomData<String>>(), 0);
    }
}
